//
//  OCRouter.m
//  OCRouter
//
//  Created by hanbing on 2017/10/16.
//  Copyright © 2017年 TZ. All rights reserved.
//

#import "OCRouter.h"


@implementation OCRouter

+ (instancetype)sharedInstance
{
    static OCRouter *mediator;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        mediator = [[OCRouter alloc] init];
    });
    return mediator;
}

#pragma mark -
- (id)openUrl:(NSString *)urlStr {
    NSURL *url = [NSURL URLWithString:urlStr];
    NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
    NSString *urlString = [url query];
    for (NSString *param in [urlString componentsSeparatedByString:@"&"]) {
        NSArray *elts = [param componentsSeparatedByString:@"="];
        if([elts count] < 2) continue;
        
        id firstEle = [elts firstObject];
        id lastEle = [elts lastObject];
        
        if (firstEle && lastEle) {
            [params setObject:lastEle forKey:firstEle];
        }
    }
    
    NSString *actionName = [url.path stringByReplacingOccurrencesOfString:@"/" withString:@""];
    if ([actionName hasPrefix:@"native"]) {
        return @(NO);
    }

    
    id result = [self performTarget:url.host action:actionName param:params];
    return result;
    
}


- (id)performTarget:(NSString *)targetName action:(NSString *)actionName param:(NSDictionary *)para {
    // 这个目标的类名字符串
    NSString *targetClassString = [NSString stringWithFormat:@"OCTarget_%@", targetName];
    NSString *actionMethondString = [NSString stringWithFormat:@"action_%@:", actionName];
    
    Class targetClass = NSClassFromString(targetClassString);
    NSObject *target = [[targetClass alloc] init];
    
    SEL action = NSSelectorFromString(actionMethondString);
    
    if ([target respondsToSelector:action]) {
        return [self safePerformAction:action target:target param:para];
    } else {
        SEL action = NSSelectorFromString(@"notFound:");
        if ([target respondsToSelector:action]) {
            return [self safePerformAction:action target:target param:para];
        } else {
            return nil;
        }
    }
}


/**
 1. 通过对象调用指定的方法
 2. 传参 para
 */
- (id)safePerformAction:(SEL)action target:(NSObject *)target param:(NSDictionary *)para {
    NSMethodSignature *methodSig = [target methodSignatureForSelector:action];
    const char *retType = [methodSig methodReturnType];
    
    if (methodSig == nil) {
        return nil;
    }
    
    // id 是可以返回任意对象 所以 我们单独处理基本变量 NSInteger BOOL void...
    // void  NSInteger BOOL CGFloat NSUInteger
    
    if (strcmp(retType, @encode(void)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&para atIndex:2];
        [invocation setTarget:target];
        [invocation setSelector:action];
        [invocation invoke];
        NSInteger result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }
    
    if (strcmp(retType, @encode(NSInteger)) ==0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&para atIndex:2]; // 为什么传2，已经传了target和action
        [invocation setTarget:target];
        [invocation setSelector:action];
        [invocation invoke];
        NSInteger result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }
    
    if (strcmp(retType, @encode(NSUInteger)) ==0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&para atIndex:2];
        [invocation setTarget:target];
        [invocation setSelector:action];
        [invocation invoke];
        NSInteger result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }
    
    if (strcmp(retType, @encode(BOOL)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&para atIndex:2];
        [invocation setTarget:target];
        [invocation setSelector:action];
        [invocation invoke];
        NSInteger result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }
    
    if (strcmp(retType, @encode(CGFloat)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&para atIndex:2];
        [invocation setTarget:target];
        [invocation setSelector:action];
        [invocation invoke];
        NSInteger result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }
    
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    return [target performSelector:action withObject:target withObject:para];
    #pragma clang diagnostic pop
}

- (NSInteger)test{
    return  1;
}

@end
